// app/manager/dy_service_manager.go
package douyin

import (
	"BlazeRider-backend/app/manager"
	"BlazeRider-backend/app/models"
	"BlazeRider-backend/app/utils"
	"BlazeRider-backend/config"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"sort"
	"strings"
)

// 1. 添加dySigner的明确定义（保持包内可见）
type dySigner struct {
	appSecret string
}

// 基础响应结构（处理公共字段）
type RoomInfoBaseResponse struct {
	Errcode    int             `json:"errcode"`
	Errmsg     string          `json:"errmsg"`
	Data       json.RawMessage `json:"data"` // 延迟解析
	StatusCode int             `json:"status_code"`
}

// 成功时的Data结构
type RoomInfoSuccessData struct {
	Info struct {
		RoomID       json.Number `json:"room_id"` // 保持数值类型
		AnchorOpenID string      `json:"anchor_open_id"`
		AvatarURL    string      `json:"avatar_url"`
		NickName     string      `json:"nick_name"`
	} `json:"info"`
}

// 错误时的Data结构
type RoomInfoErrorData struct {
	Detail  string `json:"detail"`
	SubCode int    `json:"sub_code"`
}

type DouYinFailData struct {
	RoomID  string `json:"room_id"`
	MsgType string `json:"msg_type"`
	Payload string `json:"payload"`
}

// 2. 确保签名方法正确定义
func (s *dySigner) signParams(params map[string]string) map[string]string {
	// 原有签名逻辑保持不变
	// 1. 参数排序
	keys := make([]string, 0, len(params))
	for k := range params {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// 2. 拼接参数
	var builder strings.Builder
	for _, k := range keys {
		builder.WriteString(k)
		builder.WriteString("=")
		builder.WriteString(params[k])
		builder.WriteString("&")
	}
	queryString := strings.TrimSuffix(builder.String(), "&")

	// 3. HMAC-SHA256签名
	h := hmac.New(sha256.New, []byte(s.appSecret))
	h.Write([]byte(queryString))
	signature := hex.EncodeToString(h.Sum(nil))

	// 4. 添加签名参数
	params["signature"] = signature
	return params
}

// GetDouyinToken 获取抖音access_token
// appID: 小程序ID
// appSecret: 小程序密钥
func GetDouyinToken() (accessToken string, expiresIn int, err error) {
	apiURL := config.Get().Douyin.APIBaseURL + "/api/apps/v2/token" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		AppID     string `json:"appid"`
		GrantType string `json:"grant_type"`
		Secret    string `json:"secret"`
	}{
		AppID:     config.Get().Douyin.AppID,
		GrantType: "client_credential", // 固定值
		Secret:    config.Get().Douyin.AppSecret,
	}

	// 设置请求头
	headers := map[string]string{
		"Content-Type": "application/json",
	}

	// 定义响应结构
	var response struct {
		ErrNo   int    `json:"err_no"`
		ErrTips string `json:"err_tips"`
		Data    struct {
			AccessToken string `json:"access_token"`
			ExpiresIn   int    `json:"expires_in"`
		} `json:"data"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		return "", 0, fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return "", 0, fmt.Errorf("抖音接口错误[%d]: %s", response.ErrNo, response.ErrTips)
	}

	fmt.Printf("生成抖音Token : %s,  请求url : %s, requestBody : %v, headers : %v", response.Data.AccessToken,
		apiURL, requestBody, headers,
	)

	return response.Data.AccessToken, response.Data.ExpiresIn, nil
}

// StartDouYinLiveRoomAllTask 开启直播间全部推送任务
func StartDouYinLiveRoomAllTask(accessToken string, liveRoomId string) (err error) {
	//"直播间消息类型，需要前置申请开通了对应类型直播间数据能力才可以调用。
	//1. 评论：live_comment
	//2. 礼物：live_gift
	//3. 点赞：live_like"
	//4. 粉丝团：live_fansclub"

	const liveCommentType = "live_comment"
	const LiveGiftType = "live_gift"
	const LiveLikeType = "live_like"
	const LiveFansType = "live_fansclub"

	err = StartDouYinLiveRoomSingleTask(accessToken, liveRoomId, liveCommentType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 开启评论推送出错 : ", err)

	}
	fmt.Println("直播间", liveRoomId, " 已经开通评论推送")

	err = StartDouYinLiveRoomSingleTask(accessToken, liveRoomId, LiveGiftType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 开启礼物推送出错 : ", err)

	}
	fmt.Println("直播间", liveRoomId, " 已经开通礼物推送")

	err = StartDouYinLiveRoomSingleTask(accessToken, liveRoomId, LiveLikeType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 开启点赞推送出错 : ", err)

	}
	fmt.Println("直播间", liveRoomId, " 已经开通点赞推送")

	err = StartDouYinLiveRoomSingleTask(accessToken, liveRoomId, LiveFansType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 开启粉丝团推送出错 : ", err)

	}
	fmt.Println("直播间", liveRoomId, " 已经开通粉丝团推送")

	return nil
}

// StartDouYinLiveRoomSingleTask 开启直播间单个推送任务
func StartDouYinLiveRoomSingleTask(accessToken string, liveRoomId string, taskType string) (err error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/live_data/task/start" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		RoomId  string `json:"roomid"`
		Appid   string `json:"appid"`
		MsgType string `json:"msg_type"`
	}{
		RoomId:  liveRoomId,
		Appid:   config.Get().Douyin.AppID,
		MsgType: taskType,
	}

	// 设置请求头
	headers := map[string]string{
		"content-type": "application/json",
		"access-token": accessToken,
	}

	// 定义响应结构
	var response struct {
		ErrNo  int    `json:"err_no"`
		ErrMsg string `json:"err_msg"`
		LogId  string `json:"logid"`
		Data   struct {
			TaskId string `json:"task_id"`
		} `json:"data"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		fmt.Println("请求失败", apiURL, requestBody, headers, err)
		return fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return fmt.Errorf("抖音接口错误[%d]: %s, 流水：%s", response.ErrNo, response.ErrMsg, response.LogId)
	}

	return nil
}

// StopDouYinLiveRoomAllTask 停止直播间全部推送任务
func StopDouYinLiveRoomAllTask(accessToken string, liveRoomId string) (err error) {
	//"直播间消息类型，需要前置申请开通了对应类型直播间数据能力才可以调用。
	//1. 评论：live_comment
	//2. 礼物：live_gift
	//3. 点赞：live_like"
	//4. 粉丝团：live_fansclub"

	const liveCommentType = "live_comment"
	const LiveGiftType = "live_gift"
	const LiveLikeType = "live_like"
	const LiveFansType = "live_fansclub"

	err = StopDouYinLiveRoomSingleTask(accessToken, liveRoomId, liveCommentType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 关闭评论推送出错 : ", err)

	}
	fmt.Println("直播间", liveRoomId, " 已经关闭评论推送")

	err = StopDouYinLiveRoomSingleTask(accessToken, liveRoomId, LiveGiftType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 关闭礼物推送出错 : ", err)
	}
	fmt.Println("直播间", liveRoomId, " 已经关闭礼物推送")

	err = StopDouYinLiveRoomSingleTask(accessToken, liveRoomId, LiveLikeType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 关闭点赞推送出错 : ", err)
	}
	fmt.Println("直播间", liveRoomId, " 已经关闭点赞推送")

	err = StopDouYinLiveRoomSingleTask(accessToken, liveRoomId, LiveFansType)
	if err != nil {
		fmt.Println("直播间", liveRoomId, " 关闭粉丝团推送出错 : ", err)
	}
	fmt.Println("直播间", liveRoomId, " 已经关闭粉丝团推送")

	return nil
}

// StopDouYinLiveRoomSingleTask 停止直播间单个推送任务
func StopDouYinLiveRoomSingleTask(accessToken string, liveRoomId string, taskType string) (err error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/live_data/task/stop" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		RoomId  string `json:"roomid"`
		Appid   string `json:"appid"`
		MsgType string `json:"msg_type"`
	}{
		RoomId:  liveRoomId,
		Appid:   config.Get().Douyin.AppID,
		MsgType: taskType,
	}

	// 设置请求头
	headers := map[string]string{
		"content-type": "application/json",
		"access-token": accessToken,
	}

	// 定义响应结构
	var response struct {
		ErrNo  int    `json:"err_no"`
		ErrMsg string `json:"err_msg"`
		LogId  string `json:"logid"`
		Data   struct {
			TaskId string `json:"task_id"`
		} `json:"data"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		return fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return fmt.Errorf("抖音接口错误[%d]: %s, 流水：%s", response.ErrNo, response.ErrMsg, response.LogId)
	}

	return nil
}

// SyncGameStatusToDouYin 同步对局状态给抖音
func SyncGameStatusToDouYin(accessToken string, anchorOpenId string, liveRoomId string, times int, startTime int64, endTime int64, status int, resultList []models.SyncGameGroupResultToDouYinBody) (err error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/gaming_con/round/sync_status" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		AnchorOpenId    string                                   `json:"anchor_open_id"`
		Appid           string                                   `json:"app_id"`
		RoomId          string                                   `json:"room_id"`
		RoundId         int64                                    `json:"round_id"`
		StartTime       int64                                    `json:"start_time"` // 本局开始时间，秒级时间戳
		EndTime         int64                                    `json:"end_time"`   // 本局结束时间，秒级时间戳。同步的对局状态为对局结束时，该字段必传。
		Status          int                                      `json:"status"`     // 当前房间的游戏对局状态（1=已开始、2=已结束）
		GroupResultList []models.SyncGameGroupResultToDouYinBody `json:"group_result_list"`
	}{
		AnchorOpenId:    anchorOpenId,
		Appid:           config.Get().Douyin.AppID,
		RoomId:          liveRoomId,
		RoundId:         int64(times),
		StartTime:       startTime,
		EndTime:         endTime,
		Status:          status,
		GroupResultList: resultList,
	}

	// 设置请求头
	headers := map[string]string{
		"content-type": "application/json",
		"X-Token":      accessToken,
	}

	// 定义响应结构
	var response struct {
		ErrNo  int    `json:"errcode"`
		ErrMsg string `json:"errmsg"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		return fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return fmt.Errorf("抖音接口错误[%d]: %s, 请求url: %s, requstBody : %v, headers : %v ", response.ErrNo, response.ErrMsg,
			apiURL, requestBody, headers,
		)
	}

	fmt.Println("同步抖音直播间 状态 : ", status, ", 直播id : ", liveRoomId, " , 成功")
	return nil
}

// SyncUserGroupToDouYin 同步用户选择阵营给抖音
func SyncUserGroupToDouYin(accessToken string, liveRoomId string, times int, groupId string, openId string) (err error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/gaming_con/round/upload_user_group_info" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		Appid   string `json:"app_id"`
		GroupId string `json:"group_id"`
		OpenId  string `json:"open_id"`
		RoomId  string `json:"room_id"`
		RoundId int64  `json:"round_id"`
	}{
		Appid:   config.Get().Douyin.AppID,
		GroupId: groupId,
		OpenId:  openId,
		RoomId:  liveRoomId,
		RoundId: int64(times),
	}

	// 设置请求头
	headers := map[string]string{
		"content-type": "application/json",
		"X-Token":      accessToken,
	}

	// 定义响应结构
	var response struct {
		ErrNo  int    `json:"errcode"`
		ErrMsg string `json:"errmsg"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		return fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return fmt.Errorf("抖音接口错误[%d]: %s", response.ErrNo, response.ErrMsg)
	}

	fmt.Println("同步抖音直播间 用户 : ", openId, ", 阵营 : ", groupId, ", 直播id : ", liveRoomId, " , 成功")
	return nil
}

// UploadUserGameResult 同步用户的对局数据给抖音
func UploadUserGameResult(accessToken string, anchorOpenId string, liveRoomId string, times int, userResultList []models.UploadUserGameResultUserBody) (err error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/gaming_con/round/upload_user_result" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		AnchorOpenId string                                `json:"anchor_open_id"`
		Appid        string                                `json:"app_id"`
		RoomId       string                                `json:"room_id"`
		RoundId      int64                                 `json:"round_id"`
		UserList     []models.UploadUserGameResultUserBody `json:"user_list"`
	}{
		AnchorOpenId: anchorOpenId,
		Appid:        config.Get().Douyin.AppID,
		RoomId:       liveRoomId,
		RoundId:      int64(times),
		UserList:     userResultList,
	}

	// 设置请求头
	headers := map[string]string{
		"content-type": "application/json",
		"X-Token":      accessToken,
	}

	// 定义响应结构
	var response struct {
		ErrNo  int    `json:"errcode"`
		ErrMsg string `json:"errmsg"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		return fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return fmt.Errorf("抖音接口错误[%d]: %s, 请求url: %s, requstBody : %v, headers : %v ", response.ErrNo, response.ErrMsg,
			apiURL, requestBody, headers,
		)
	}

	fmt.Println("上传抖音对局用户数据 ", ",直播id : ", liveRoomId, " , 成功")
	return nil
}

// UploadUserGameResultFinish 标志同步用户的对局数据结束标识给抖音
func UploadUserGameResultFinish(accessToken string, anchorOpenId string, liveRoomId string, times int, completeTimeStamp int64) (err error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/gaming_con/round/complete_upload_user_result" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		AnchorOpenId      string `json:"anchor_open_id"`
		Appid             string `json:"app_id"`
		RoomId            string `json:"room_id"`
		RoundId           int64  `json:"round_id"`
		CompleteTimeStamp int64  `json:"complete_time"`
	}{
		AnchorOpenId: anchorOpenId,
		Appid:        config.Get().Douyin.AppID,
		RoomId:       liveRoomId,
		RoundId:      int64(times),
	}

	if completeTimeStamp > 0 {
		requestBody.CompleteTimeStamp = completeTimeStamp
	}

	// 设置请求头
	headers := map[string]string{
		"content-type": "application/json",
		"X-Token":      accessToken,
	}

	// 定义响应结构
	var response struct {
		ErrNo  int    `json:"errcode"`
		ErrMsg string `json:"errmsg"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		return fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return fmt.Errorf("抖音接口错误[%d]: %s, 请求url: %s, requstBody : %v, headers : %v ", response.ErrNo, response.ErrMsg,
			apiURL, requestBody, headers,
		)
	}

	fmt.Println("上传抖音对局用户数据完结标志 ", "直播id : ", liveRoomId, " , 成功")
	return nil
}

// UploadGameRankResult 同步对局的排行榜数据给抖音
func UploadGameRankResult(accessToken string, anchorOpenId string, liveRoomId string, times int, userRankResultList []models.UploadGameRankResultBody) (err error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/gaming_con/round/upload_rank_list" // 沙盒环境

	// 构建请求参数
	requestBody := struct {
		AnchorOpenId string                            `json:"anchor_open_id"`
		Appid        string                            `json:"app_id"`
		RoomId       string                            `json:"room_id"`
		RoundId      int64                             `json:"round_id"`
		RankList     []models.UploadGameRankResultBody `json:"rank_list"`
	}{
		AnchorOpenId: anchorOpenId,
		Appid:        config.Get().Douyin.AppID,
		RoomId:       liveRoomId,
		RoundId:      int64(times),
		RankList:     userRankResultList,
	}

	// 设置请求头
	headers := map[string]string{
		"content-type": "application/json",
		"X-Token":      accessToken,
	}

	// 定义响应结构
	var response struct {
		ErrNo  int    `json:"errcode"`
		ErrMsg string `json:"errmsg"`
	}

	// 发送请求
	if err := utils.Post(apiURL, requestBody, headers, &response); err != nil {
		return fmt.Errorf("请求失败: %w", err)
	}

	// 处理错误码
	if response.ErrNo != 0 {
		if response.ErrNo == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		return fmt.Errorf("抖音接口错误[%d]: %s, 请求url: %s, requstBody : %v, headers : %v ", response.ErrNo, response.ErrMsg,
			apiURL, requestBody, headers,
		)
	}

	fmt.Println("上传抖音对局榜单列表数据 ", ",直播id : ", liveRoomId, " , 成功")
	return nil
}

func GetDouYinRoomInfo(accessToken, clientToken string) (*models.LiveRoomUserInfo, error) {
	apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/webcastmate/info"

	// 构建请求体（保持原有结构）
	requestBody := struct {
		Token string `json:"token"`
	}{
		Token: clientToken,
	}

	// 设置请求头（自动处理Content-Type）
	headers := map[string]string{
		"X-Token": accessToken, // 网页6提到的自定义头设置
	}

	// 调用优化后的Post方法（网页6的Post方法实现）
	var baseResp RoomInfoBaseResponse
	if err := utils.Post(apiURL, requestBody, headers, &baseResp); err != nil {
		// 处理HTTP错误（网页5的错误处理机制）
		if httpErr, ok := err.(*utils.HTTPError); ok {
			return nil, fmt.Errorf("HTTP请求失败[%d]: %s | 响应内容: %s",
				httpErr.StatusCode, httpErr.Status, httpErr.Body)
		}
		return nil, fmt.Errorf("网络请求失败: %w", err)
	}

	// 处理业务错误（网页1的错误码处理逻辑）
	if baseResp.Errcode != 0 {
		if baseResp.Errcode == 40004 {
			// 抖音接口错误[40004]: access token is expired
			manager.Get().DyTokenManager().ExpireCanUseToken()
			fmt.Println("由于抖音token失效，已经 重置 douyin token")
		}
		var errData RoomInfoErrorData
		if json.Unmarshal(baseResp.Data, &errData) == nil {
			return nil, fmt.Errorf("抖音接口错误[%d]: %s (子码%d)",
				baseResp.Errcode, baseResp.Errmsg, errData.SubCode)
		}
		return nil, fmt.Errorf("抖音接口错误[%d]: %s", baseResp.Errcode, baseResp.Errmsg)
	}

	// 解析成功数据（网页8的JSON解析机制）
	var successData RoomInfoSuccessData
	if err := json.Unmarshal(baseResp.Data, &successData); err != nil {
		return nil, fmt.Errorf("数据解析失败: %w", err)
	}

	// 转换数值型RoomID（网页1的数据处理方式）
	//roomID := strconv.FormatInt(int64(successData.Info.RoomID), 10)
	roomID := successData.Info.RoomID.String()

	return &models.LiveRoomUserInfo{
		RoomId:       roomID,
		AnchorOpenId: successData.Info.AnchorOpenID,
		AvatarUrl:    successData.Info.AvatarURL,
		NickName:     successData.Info.NickName,
	}, nil
}

func GetDouYinMissedGiftRecord(liveRoomId, accessToken string, pageNum, pageSize int) ([]models.GiftRequestPayload, int, error) {
	requestTrue := true

	baseResp := struct {
		ErrNo  int             `json:"err_no"`
		ErrMsg string          `json:"err_msg"`
		LogId  string          `json:"logid"`
		Data   json.RawMessage `json:"data"`
	}{}

	if requestTrue {
		apiURL := config.Get().Douyin.APIWebcastBaseURL + "/api/live_data/task/fail_data/get"

		// 构建请求体（保持原有结构）
		requestBody := struct {
			RoomId   string `json:"roomid"`
			Appid    string `json:"appid"`
			MsgType  string `json:"msg_type"`
			PageNum  int    `json:"page_num"`
			PageSize int    `json:"page_size"`
		}{
			RoomId:   liveRoomId,
			Appid:    config.Get().Douyin.AppID,
			MsgType:  "live_gift",
			PageNum:  pageNum,
			PageSize: pageSize,
		}

		// 设置请求头（自动处理Content-Type）
		headers := map[string]string{
			"access-token": accessToken, // 网页6提到的自定义头设置
		}

		// 调用优化后的Post方法（网页6的Post方法实现）

		if err := utils.Post(apiURL, requestBody, headers, &baseResp); err != nil {
			// 处理HTTP错误（网页5的错误处理机制）
			if httpErr, ok := err.(*utils.HTTPError); ok {
				return nil, 0, fmt.Errorf("HTTP请求失败[%d]: %s | 响应内容: %s",
					httpErr.StatusCode, httpErr.Status, httpErr.Body)
			}
			return nil, 0, fmt.Errorf("网络请求失败: %w", err)
		}
	}

	//上面是正常请求，下面这句是请求mock数据
	if !requestTrue {
		mockStr := GetDouYinMissedGiftRecordMock(liveRoomId, accessToken, pageNum, pageSize)
		if err := json.Unmarshal([]byte(mockStr), &baseResp); err != nil {
			fmt.Println("解析模拟数据失败: ", err) // 或更温和的错误处理
			return nil, 0, fmt.Errorf("解析模拟数据失败: %w",
				err)
		}
	}

	// 处理业务错误（网页1的错误码处理逻辑）
	if baseResp.ErrNo != 0 {
		return nil, 0, fmt.Errorf("抖音查询失败礼物接口错误[%d]: %s (logId:%s)",
			baseResp.ErrNo, baseResp.ErrMsg, baseResp.LogId)
	}

	// 解析成功数据（网页8的JSON解析机制）
	var formatData models.LiveRoomFailGiftData
	if err := json.Unmarshal(baseResp.Data, &formatData); err != nil {
		return nil, 0, fmt.Errorf("数据解析失败: %w", err)
	}

	var returnData []models.GiftRequestPayload
	for _, data := range formatData.DataList {
		var rawPayload string
		// 第一步：解码外层 JSON 字符串
		if err := json.Unmarshal(data.Payload, &rawPayload); err != nil {
			return nil, 0, fmt.Errorf("外层数据解析失败: %w", err)
		}

		var formatPayload models.GiftRequestPayload
		// 第二步：解码内层真正的 JSON 数据
		if err := json.Unmarshal([]byte(rawPayload), &formatPayload); err != nil {
			return nil, 0, fmt.Errorf("内层数据解析失败: %w", err)
		}

		returnData = append(returnData, models.GiftRequestPayload{
			MsgID:     formatPayload.MsgID,
			SecOpenID: formatPayload.SecOpenID,
			SecGiftId: formatPayload.SecGiftId,
			GiftNum:   formatPayload.GiftNum,
			GiftValue: formatPayload.GiftValue,
			AvatarURL: formatPayload.AvatarURL,
			Nickname:  formatPayload.Nickname,
			Timestamp: formatPayload.Timestamp,
		})
	}

	return returnData, formatData.TotalCount, nil
}

func GetDouYinMissedGiftRecordMock(liveRoomId, accessToken string, pageNum, pageSize int) string {
	if liveRoomId != "111" {
		return ""
	}
	payload1 := []models.GiftRequestPayload{
		{
			MsgID:     "1234567890",
			SecOpenID: "OPENID_0001",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   5,
			GiftValue: 500,
			AvatarURL: "https://example.com/avatar1.jpg",
			Nickname:  "用户1",
			Timestamp: 1745381347000,
		},
		{
			MsgID:     "1234567891",
			SecOpenID: "OPENID_0002",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   3,
			GiftValue: 300,
			AvatarURL: "https://example.com/avatar2.jpg",
			Nickname:  "用户2",
			Timestamp: 1745381347001,
		},
		{
			MsgID:     "1234567892",
			SecOpenID: "OPENID_0003",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   8,
			GiftValue: 800,
			AvatarURL: "https://example.com/avatar3.jpg",
			Nickname:  "用户3",
			Timestamp: 1745381347002,
		},
		{
			MsgID:     "1234567893",
			SecOpenID: "OPENID_0004",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   2,
			GiftValue: 200,
			AvatarURL: "https://example.com/avatar4.jpg",
			Nickname:  "用户4",
			Timestamp: 1745381347003,
		},
		{
			MsgID:     "1234567894",
			SecOpenID: "OPENID_0005",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   10,
			GiftValue: 1000,
			AvatarURL: "https://example.com/avatar5.jpg",
			Nickname:  "用户5",
			Timestamp: 1745381347004,
		},
		{
			MsgID:     "1234567895",
			SecOpenID: "OPENID_0006",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   7,
			GiftValue: 700,
			AvatarURL: "https://example.com/avatar6.jpg",
			Nickname:  "用户6",
			Timestamp: 1745381347005,
		},
		{
			MsgID:     "1234567896",
			SecOpenID: "OPENID_0007",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   4,
			GiftValue: 400,
			AvatarURL: "https://example.com/avatar7.jpg",
			Nickname:  "用户7",
			Timestamp: 1745381347006,
		},
		{
			MsgID:     "1234567897",
			SecOpenID: "OPENID_0008",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   6,
			GiftValue: 600,
			AvatarURL: "https://example.com/avatar8.jpg",
			Nickname:  "用户8",
			Timestamp: 1745381347007,
		},
		{
			MsgID:     "1234567898",
			SecOpenID: "OPENID_0009",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   9,
			GiftValue: 900,
			AvatarURL: "https://example.com/avatar9.jpg",
			Nickname:  "用户9",
			Timestamp: 1745381347008,
		},
		{
			MsgID:     "1234567899",
			SecOpenID: "OPENID_0010",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   1,
			GiftValue: 100,
			AvatarURL: "https://example.com/avatar10.jpg",
			Nickname:  "用户10",
			Timestamp: 1745381347009,
		},
	}

	payload2 := []models.GiftRequestPayload{
		{
			MsgID:     "3234567890",  // 注意 msg_id 前缀改为 2，避免与 payload1 冲突
			SecOpenID: "OPENID_0011", // 从 0011 开始递增
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   4,
			GiftValue: 400, // GiftNum * 100
			AvatarURL: "https://example.com/avatar11.jpg",
			Nickname:  "测试用户11",
			Timestamp: 1745381347010, // 时间戳延续自 payload1 的最后一个值 +1
		},
		{
			MsgID:     "3234567891",
			SecOpenID: "OPENID_0012",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   6,
			GiftValue: 600,
			AvatarURL: "https://example.com/avatar12.jpg",
			Nickname:  "测试用户12",
			Timestamp: 1745381347011,
		},
		{
			MsgID:     "3234567892",
			SecOpenID: "OPENID_0013",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   2,
			GiftValue: 200,
			AvatarURL: "https://example.com/avatar13.jpg",
			Nickname:  "测试用户13",
			Timestamp: 1745381347012,
		},
		{
			MsgID:     "3234567893",
			SecOpenID: "OPENID_0014",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   9,
			GiftValue: 900,
			AvatarURL: "https://example.com/avatar14.jpg",
			Nickname:  "测试用户14",
			Timestamp: 1745381347013,
		},
		{
			MsgID:     "3234567894",
			SecOpenID: "OPENID_0015",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   7,
			GiftValue: 700,
			AvatarURL: "https://example.com/avatar15.jpg",
			Nickname:  "测试用户15",
			Timestamp: 1745381347014,
		},
		{
			MsgID:     "3234567895",
			SecOpenID: "OPENID_0016",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   5,
			GiftValue: 500,
			AvatarURL: "https://example.com/avatar16.jpg",
			Nickname:  "测试用户16",
			Timestamp: 1745381347015,
		},
		{
			MsgID:     "3234567896",
			SecOpenID: "OPENID_0017",
			SecGiftId: "n1/Dg1905sj1FyoBlQBvmbaDZFBNaKuKZH6zxHkv8Lg5x2cRfrKUTb8gzMs=",
			GiftNum:   8,
			GiftValue: 800,
			AvatarURL: "https://example.com/avatar17.jpg",
			Nickname:  "测试用户17",
			Timestamp: 1745381347016,
		},
	}

	payloadArr := [][]models.GiftRequestPayload{
		payload1, // 第 0 个元素是 payload1
		payload2, // 第 1 个元素是 payload2
	}
	totalNum := 0
	for k := range payloadArr {
		totalNum = totalNum + len(payloadArr[k])
	}
	truePageNum := pageNum
	var DataList []DouYinFailData

	if pageNum > len(payloadArr) {
		truePageNum = len(payloadArr)
		DataList = []DouYinFailData{}
	} else {
		selectPayload := payloadArr[truePageNum-1]
		for i := 0; i < len(selectPayload); i++ {
			selectOnePayloadStr, _ := json.Marshal(selectPayload[i])
			// 假设selectPayload的每个元素是包含所需字段的结构体
			// 替换右侧字段名为实际字段名
			dataItem := DouYinFailData{
				RoomID:  liveRoomId,
				MsgType: "live_gift",                 // 根据实际字段名调整
				Payload: string(selectOnePayloadStr), // 根据实际字段名调整
			}
			DataList = append(DataList, dataItem)
		}

	}

	// 使用匿名结构体构建响应
	response := struct {
		ErrNo  int    `json:"err_no"`
		ErrMsg string `json:"err_msg"`
		LogID  string `json:"logid"`
		Data   struct {
			PageNum    int              `json:"page_num"`
			TotalCount int              `json:"total_count"`
			DataList   []DouYinFailData `json:"data_list"`
		} `json:"data"`
	}{
		ErrNo:  0,
		ErrMsg: "",
		LogID:  "your_log_id",
		Data: struct {
			PageNum    int              `json:"page_num"`
			TotalCount int              `json:"total_count"`
			DataList   []DouYinFailData `json:"data_list"`
		}{
			PageNum:    pageNum,
			TotalCount: totalNum,
			DataList:   DataList,
		},
	}

	jsonStr, _ := json.Marshal(response)
	return string(jsonStr)
}
